using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace CollabApp.Domain.Entities;

/// <summary>
/// 排名历史实体类 - 记录用户排名的历史变化轨迹
/// 用于分析排名趋势和历史回顾
/// </summary>
[Table("ranking_histories")]
public class RankingHistory : BaseEntity
{
    /// <summary>
    /// 用户ID - 排名变化的用户标识
    /// </summary>
    [Required]
    [Column("user_id")]
    public Guid UserId { get; private set; }

    /// <summary>
    /// 排行榜类型 - 历史记录对应的排行榜类型
    /// </summary>
    [Required]
    [Column("ranking_type")]
    public RankingType RankingType { get; private set; }

    /// <summary>
    /// 排名 - 该时间点的用户排名
    /// </summary>
    [Column("rank")]
    public int Rank { get; private set; }

    /// <summary>
    /// 分数 - 该时间点的用户分数
    /// </summary>
    [Column("score")]
    public int Score { get; private set; }

    /// <summary>
    /// 记录时间 - 该排名记录的时间点
    /// </summary>
    [Column("recorded_at")]
    public DateTime RecordedAt { get; private set; } = DateTime.UtcNow;

    // ============ 构造函数 ============

    /// <summary>
    /// 无参构造函数 - EF Core 必需
    /// </summary>
    private RankingHistory() { }

    /// <summary>
    /// 私有构造函数 - 仅限工厂方法调用
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="rankingType">排行榜类型</param>
    /// <param name="rank">排名</param>
    /// <param name="score">分数</param>
    /// <param name="recordedAt">记录时间</param>
    private RankingHistory(Guid userId, RankingType rankingType, int rank, int score, DateTime? recordedAt = null)
    {
        UserId = userId;
        RankingType = rankingType;
        Rank = rank;
        Score = score;
        RecordedAt = recordedAt ?? DateTime.UtcNow;
    }

    // ============ 导航属性 ============
    
    /// <summary>
    /// 导航属性 - 关联的用户信息
    /// </summary>
    [ForeignKey("UserId")]
    public virtual Auth.User User { get; set; } = null!;

    // ============ 工厂方法 ============

    /// <summary>
    /// 创建排名历史记录 - 工厂方法
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="rankingType">排行榜类型</param>
    /// <param name="rank">排名</param>
    /// <param name="score">分数</param>
    /// <param name="recordedAt">记录时间（可选，默认为当前时间）</param>
    /// <returns>新的排名历史记录实例</returns>
    public static RankingHistory CreateRankingHistory(Guid userId, RankingType rankingType, 
                                                       int rank, int score, DateTime? recordedAt = null)
    {
        if (userId == Guid.Empty)
            throw new ArgumentException("用户ID不能为空", nameof(userId));
        if (rank <= 0)
            throw new ArgumentException("排名必须大于0", nameof(rank));
        if (score < 0)
            throw new ArgumentException("分数不能为负数", nameof(score));

        return new RankingHistory(userId, rankingType, rank, score, recordedAt);
    }

    /// <summary>
    /// 从排行榜记录创建历史记录 - 工厂方法
    /// </summary>
    /// <param name="ranking">排行榜记录</param>
    /// <param name="recordedAt">记录时间（可选，默认为当前时间）</param>
    /// <returns>新的排名历史记录实例</returns>
    public static RankingHistory CreateFromRanking(Ranking ranking, DateTime? recordedAt = null)
    {
        if (ranking == null)
            throw new ArgumentNullException(nameof(ranking), "排行榜记录不能为空");

        return CreateRankingHistory(ranking.UserId, ranking.RankingType, ranking.CurrentRank, 
                                    ranking.Score, recordedAt);
    }

    // ============ 业务方法 ============

    /// <summary>
    /// 检查记录是否在指定时间范围内
    /// </summary>
    /// <param name="startTime">开始时间</param>
    /// <param name="endTime">结束时间</param>
    /// <returns>是否在范围内</returns>
    public bool IsWithinTimeRange(DateTime startTime, DateTime endTime)
    {
        return RecordedAt >= startTime && RecordedAt <= endTime;
    }

    /// <summary>
    /// 获取记录距今的天数
    /// </summary>
    /// <returns>天数</returns>
    public int GetDaysFromNow()
    {
        return (DateTime.UtcNow - RecordedAt).Days;
    }

    /// <summary>
    /// 检查记录是否过期（超过指定天数）
    /// </summary>
    /// <param name="days">天数阈值</param>
    /// <returns>是否过期</returns>
    public bool IsExpired(int days = 90)
    {
        return GetDaysFromNow() > days;
    }

    /// <summary>
    /// 比较两个历史记录的排名变化
    /// </summary>
    /// <param name="other">另一个历史记录</param>
    /// <returns>排名变化（正数表示排名上升，负数表示下降）</returns>
    public int CompareRankingChange(RankingHistory other)
    {
        if (other == null)
            throw new ArgumentNullException(nameof(other));
        if (other.UserId != UserId || other.RankingType != RankingType)
            throw new ArgumentException("只能比较同一用户同一类型的排名记录");

        // 排名数字越小排名越高，所以这里是反向计算
        return other.Rank - Rank;
    }

    /// <summary>
    /// 比较两个历史记录的分数变化
    /// </summary>
    /// <param name="other">另一个历史记录</param>
    /// <returns>分数变化</returns>
    public int CompareScoreChange(RankingHistory other)
    {
        if (other == null)
            throw new ArgumentNullException(nameof(other));
        if (other.UserId != UserId || other.RankingType != RankingType)
            throw new ArgumentException("只能比较同一用户同一类型的排名记录");

        return Score - other.Score;
    }

    /// <summary>
    /// 获取排行榜类型显示名称
    /// </summary>
    /// <returns>类型名称</returns>
    public string GetRankingTypeName()
    {
        return RankingType switch
        {
            RankingType.TotalScore => "总积分排行榜",
            RankingType.WeeklyScore => "周积分排行榜",
            RankingType.MonthlyScore => "月积分排行榜",
            RankingType.WinRate => "胜率排行榜",
            RankingType.Activity => "活跃度排行榜",
            _ => "未知排行榜"
        };
    }
}
